package home.minesweeper.servlet;

import java.io.IOException;
import java.util.Random;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * The <code>SetupBoard</code> class does the random generation of whether each
 * cell in MineSweeper holds a bomb or not. It then generates the values in the
 * other cells and stores them in the session.
 * 
 * @author Shivasubramanian
 *
 */
public class SetupBoard extends HttpServlet {
	
	public void doGet(HttpServletRequest req, HttpServletResponse res) {
		//System.out.println("ok... u here?");
		char row1[] = new char[8];
		char row2[] = new char[8];
		char row3[] = new char[8];
		char row4[] = new char[8];
		char row5[] = new char[8];
		char row6[] = new char[8];
		char row7[] = new char[8];
		char row8[] = new char[8];
		char rows[][] = new char[][]
		                           {row1, row2, row3, row4, row5, row6, row7,
									row8};
		doBoardSetup(rows);
		req.getSession().setAttribute("gameboard", rows);
		
		try {
			req.getRequestDispatcher("gamepage").forward(req, res);
		} catch (IOException ioe) {
			ioe.printStackTrace();
		} catch (ServletException se) {
			se.printStackTrace();
		} catch (IllegalStateException ise) {
			ise.printStackTrace();
		}
	}
	
	private void doBoardSetup(char rows[][]) {
		Random r = new Random();
		fillRequiredCellsWithBombs(r, rows);
		fillNonBombCellsWithNumbers(rows);
	}
	
	/**
	 * Iterates through each cell in the row denoted by <code>row</code>, and
	 * for each cell, determines the next boolean value generated by
	 * <code>r</code>, and if <code>true</code>, sets that cell as containing a 
	 * bomb.
	 * 
	 * @param r   the <code>Random</code> instance used to determine whether the
	 *            cell contains a bomb or not.
	 * @param row the row through which we iterate
	 */
	private void fillRequiredCellsWithBombs(Random r, char rows[][]) {
		for (int i = 0; i < 8; i++) {
			for (int j = 0; j < 8; j++) {
				if (r.nextBoolean()) {
					rows[i][j] = 'B';
				}
			}
		}
	}
	
	/**
	 * Fills those cells that do not have bombs with the count of the bombs that
	 * surround the cells. As such, this method must be called only after a call
	 * to <code>fillRequiredCellsWithBombs</code>. Otherwise, all cells will
	 * indicate that 0 bombs surround them. <br>Note that the method internally
	 * calls  <code>howManyBombsDoesThisCellHave(char[][], int, int)</code>
	 * method while iterating through each cell.
	 * 
	 * @param rows an array that holds each row. This is required since the 
	 *             method may need to move to other rows to determine if cells
	 *             that surround the current cell in those rows have bombs.
	 */
	private void fillNonBombCellsWithNumbers(char rows[][]) {
		for (int i = 0; i < 8; i++) {
			char current_row[] = rows[i];
			for (int j = 0; j < 8; j++) {
				if (current_row[j] != 'B') {
					current_row[j] = howManyBombsDoesThisCellHave(rows, i, j);
				}
			}
		}
	}
	
	/**
	 * Given a current row and a current cell, determines which among the 8
	 * cells that surround the current cell have bombs. 
	 * 
	 * @param rows         an array that holds each row. This is required since
	 *                     the method may need to move to other rows to
	 *                     determine if cells that surround the current cell in
	 *                     those rows have bombs.
	 * @param current_row  the counter that indicates which is the current row
	 * @param current_cell the counter that indicates which is the current cell
	 *                     in <code>current_row</code>
	 * @return             the number of bombs that surround the current cell
	 */
	private char howManyBombsDoesThisCellHave(
			char rows[][], int current_row, int current_cell) {
		int sumOfBombs = 0;
		//Do cells on either side of the current cell have bombs?
		if (current_cell > 0) {
			sumOfBombs += rows[current_row][current_cell - 1] == 'B'? 1 : 0;
		}
		if (current_cell < 7) {
			sumOfBombs += rows[current_row][current_cell + 1] == 'B'? 1 : 0;
		}
		
		//Do cells to the upper left, upper right and directly above our cell
		//have bombs?
		if (current_row > 0) {
			if (current_cell > 0) {
				sumOfBombs +=
					rows[current_row - 1][current_cell - 1] == 'B'? 1 : 0;
			}
			sumOfBombs += rows[current_row - 1][current_cell] == 'B'? 1 : 0;
			if (current_cell < 7) {
				sumOfBombs +=
					rows[current_row - 1][current_cell + 1] == 'B'? 1 : 0;
			}
		}
		
		//Do cells to the bottom left, bottom right and directly below our cell
		//have bombs?
		if (current_row < 7) {
			if (current_cell > 0) {
				sumOfBombs +=
					rows[current_row + 1][current_cell - 1] == 'B'? 1 : 0;
			}
			sumOfBombs += rows[current_row + 1][current_cell] == 'B'? 1 : 0;
			if (current_cell < 7) {
				sumOfBombs +=
					rows[current_row + 1][current_cell + 1] == 'B'? 1 : 0;
			}
		}
		return Integer.toString(sumOfBombs).charAt(0);
	}
}
